package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.DeptDto;
import com.zzyl.entity.Dept;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeptMapper;
import com.zzyl.mapper.PostMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.service.DeptService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.ThreadLocalUtil;
import com.zzyl.vo.DeptVo;
import com.zzyl.vo.TreeItemVo;
import com.zzyl.vo.TreeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 部门表服务实现类
 */
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    DeptMapper deptMapper;
    @Autowired
    private PostMapper postMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * @param deptDto 对象信息
     * @return DeptVo
     * 创建部门表
     */
    @Transactional
    @Override
    public void createDept(DeptDto deptDto) {
        //转换deptDto为Dept
        Dept dept = BeanUtil.toBean(deptDto, Dept.class);

        //根据传递过来的父部门编号创建当前部门编号
        String deptNo = createDeptNo(dept.getParentDeptNo());
        dept.setDeptNo(deptNo);

        //保存
        int flag = deptMapper.insert(dept);
        if (flag != 1) {
            throw new RuntimeException("保存部门信息出错");
        }

        //如果当前leader也是其他其他部门的负责人，则清空其他部门的leader数据
        //一个人只能是一个部门的leader
        if (ObjectUtil.isNotEmpty(deptDto.getLeaderId())) {

            //根据leader查询，如果存在，则清空
            deptMapper.clearOtherDeptLeader(deptDto.getLeaderId(), deptNo);
        }
    }

    /**
     * @param deptDto 对象信息
     */
    @Transactional
    @Override
    public void updateDept(DeptDto deptDto) {
        //转换DeptVo为Dept
        Dept dept = BeanUtil.toBean(deptDto, Dept.class);

        //TODO 检验  部门存在用户,不允许禁用  已完成
        if (dept.getDataState().equals("1")) {
            if (checkDeptExistUser(dept.getDeptNo())) {
                throw new RuntimeException("部门存在用户,不允许禁用");
            }
        }

        //修改
        int flag = deptMapper.updateByPrimaryKey(dept);
        if (flag == 0) {
            throw new RuntimeException("修改部门信息出错");
        }

        //如果当前leader也是其他其他部门的负责人，则清空其他部门的leader数据
        //一个人只能是一个部门的leader
        if (ObjectUtil.isNotEmpty(deptDto.getLeaderId())) {
            //根据leader查询，如果存在，则清空
            deptMapper.clearOtherDeptLeader(deptDto.getLeaderId(), deptDto.getDeptNo());
        }
    }

    @Autowired
    private UserMapper userMapper;

    /**
     * 查询部门是否存在用户
     */
    public boolean checkDeptExistUser(String postNo) {
        int result = userMapper.checkDeptExistUser(postNo);
        return result > 0;
    }

    /**
     * @param deptDto 多条件查询部门表列表
     * @return: List<DeptVo>
     */
    @Override
    public List<DeptVo> findDeptList(DeptDto deptDto) {
        List<Dept> deptList = deptMapper.selectList(deptDto);
        List<DeptVo> deptVos = BeanUtil.copyToList(deptList, DeptVo.class);
        deptVos.forEach(v -> v.setCreateDay(LocalDateTimeUtil.format(v.getCreateTime(), "yyyy-MM-dd")));
        return deptVos;
    }


    @Override
    public List<DeptVo> findDeptInDeptNos(List<String> deptNos) {
        List<Dept> depts = deptMapper.findDeptInDeptNos(deptNos);
        return BeanUtil.copyToList(depts, DeptVo.class);
    }


    @Override
    public String createDeptNo(String parentDeptNo) {
        if (NoProcessing.processString(parentDeptNo).length() / 3 == 5) {
            throw new BaseException(BasicEnum.DEPT_DEPTH_UPPER_LIMIT);
        }
        DeptDto deptDto = DeptDto.builder().parentDeptNo(parentDeptNo).build();
        List<Dept> deptList = deptMapper.selectList(deptDto);
        //无下属节点则创建下属节点
        if (ObjectUtil.isEmpty(deptList)) {
            return NoProcessing.createNo(parentDeptNo, false);
            //有下属节点则累加下属节点
        } else {
            Long deptNo = deptList.stream()
                    .map(dept -> Long.valueOf(dept.getDeptNo()))
                    .max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(String.valueOf(deptNo), true);
        }
    }

    @Override
    public List<DeptVo> findDeptVoListInRoleId(List<Long> roleIdSet) {
        return deptMapper.findDeptVoListInRoleId(roleIdSet);
    }

    @Transactional
    @Override
    public void deleteByDeptNo(String deptNo) {
        if (hasChildByDeptNo(deptNo)) {
            throw new RuntimeException("存在下级部门,不允许删除");
        }
        //TODO  部门存在用户,不允许删除
        if (checkDeptExistUser(deptNo)) {
            throw new RuntimeException("部门存在用户,不允许禁用");
        }

        deptMapper.deleteByDeptNo(deptNo);
        postMapper.deleteByDeptNo(deptNo);
    }

    /**
     * 启用-禁用部门
     *
     * @param deptDto
     * @return
     */
    @Override
    public void isEnable(DeptDto deptDto) {

        //1.启用部门
        if (deptDto.getDataState().equals("0")) {
            //1.1 判断父级菜单是否是禁用，如果是禁用，不允许启用
            String parentDeptNo = deptDto.getParentDeptNo();
            Dept deptParent = deptMapper.selectByDeptNo(parentDeptNo);
            if (deptParent != null && deptParent.getDataState().equals("1")) {
                throw new BaseException(BasicEnum.PARENT_DEPT_DISABLE);
            }
        }

        //TODO 如果部门下有用户，则不允许禁用 已完成
        //如果部门下有用户，则不允许禁用
        if (deptDto.getDataState().equals("1")) {
            Integer count = userMapper.checkDeptExistUser(deptDto.getDeptNo());
            if (count > 0) {
                throw new BaseException(BasicEnum.DEPT_BINDING_USER);
            }
        }

        //判断是否有子菜单，如果有子菜单，则一起启用或禁用
        String deptNo = deptDto.getDeptNo();
        deptMapper.updateByDeptNo(deptNo, deptDto.getDataState());
        deptMapper.updateByParentDeptNo(NoProcessing.processString(deptNo), deptDto.getDataState());
    }

    /**
     * 是否存在子节点
     *
     * @param deptNo
     * @return 结果
     */
    public boolean hasChildByDeptNo(String deptNo) {
        int result = deptMapper.hasChildByDeptNo(deptNo);
        return result > 0;
    }

    /**
     * 组织部门树形
     *
     * @return: deptDto
     */
    @Override
    public TreeVo deptTreeVo(DeptDto dto) {

        Long id = ThreadLocalUtil.get();
        String redisKey = "zzyl:dept:resource:tree";

        String redisData = stringRedisTemplate.opsForValue().get(redisKey);

        if (StrUtil.isNotEmpty(redisData)) {
            return JSON.parseObject(redisData, TreeVo.class);
        }
        //1. 查询部门列表数据
        dto.setDataState(SuperConstant.DATA_STATE_0); //状态0启用
        List<Dept> deptList = deptMapper.selectList(dto); //每一个数据就是一个节点

        if (ObjectUtil.isEmpty(deptList)) {
            throw new RuntimeException("部门数据没有定义！");
        }
        //找根节点
        Dept rootDept = CollUtil.findOneByField(deptList, "parentDeptNo", SuperConstant.ROOT_DEPT_PARENT_ID);

        //递归调用，返回一颗树，参数说明：第一个参数表示根节点，第二个参数表示的是所有节点
        TreeItemVo treeItemVo = recursionTreeItem(rootDept, deptList);

        //返回
        TreeVo treeVo = TreeVo.builder()
                .items(List.of(treeItemVo))  //需要将树放进集合中，赋值给items
                .build();

        stringRedisTemplate.opsForValue().set(redisKey, JSON.toJSONString(treeVo));

        return treeVo;
    }

    /**
     * 构建树形结构，递归调用
     *
     * @param deptRoot 当前部门
     * @param deptList 部门列表（全部数据）
     */
    private TreeItemVo recursionTreeItem(Dept deptRoot, List<Dept> deptList) {
        //1. 构建树形结构对象
        TreeItemVo treeItemVo = TreeItemVo.builder()
                .id(deptRoot.getDeptNo()).label(deptRoot.getDeptName()).build();

        //2. 获得当前部门deptRoot下子部门
        Collection<Dept> collection = CollUtil.filterNew(deptList, dept -> dept.getParentDeptNo().equals(deptRoot.getDeptNo()));

        //如果子节点为空，直接返回

        if (ObjectUtil.isEmpty(collection)) {
            return treeItemVo;
        }
        //如果子节点不为空，需要将集合中的 Dept 转换为 TreeItemVo

        List<TreeItemVo> children = collection.stream()
                .map(dept -> recursionTreeItem(dept, deptList))
                .collect(Collectors.toList());
        treeItemVo.setChildren(children);
        return treeItemVo;
    }

    @Override
    public boolean isLowestDept(String dept) {
        int count = deptMapper.isLowestDept(dept);
        return count > 0;
    }
}
